package view;

import java.awt.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;

/**
 * This class is a wrap-up of the classic BufferedImage class. It provides
 * simplified accessing method for RGB image. You may want to display this image
 * by enclosing it into an ImageFrame object.
 * 
 * @author nicolas 20070919
 * 
 */
public class ImageBuffer extends BufferedImage {

	public ImageBuffer(int width, int height) {
		super(width, height, BufferedImage.TYPE_INT_ARGB);
	}

	static public ImageBuffer loadFromDisk(String __filename) {
		ImageBuffer image = null;
		try {
			BufferedImage bi = ImageIO.read(new File(__filename));
			image = new ImageBuffer(bi.getWidth(), bi.getHeight());
			for (int x = 0; x != bi.getWidth(); x++)
				for (int y = 0; y != bi.getHeight(); y++)
					image.setRGB(x, y, bi.getRGB(x, y));
		} catch (IOException e) {
			System.err.println("[error] image \"" + __filename
					+ "\" could not be loaded.");
		}
		return image;
	}

	/**
	 * save current image buffer to PNG file.
	 * 
	 * @param __filename
	 *            output filename without extension
	 */
	public void saveToDisk(String __filename) {
		try {
			ImageIO.write(this, "png", new File(__filename + ".png"));
		} catch (IOException e) {
			System.err.println("[error] image \"" + __filename
					+ "\" could not be written to disk.");
		}
	}

	/**
	 * set target pixel color (RGB) -- color values btw 0 and 255
	 * 
	 * @param x
	 * @param y
	 * @param rgb
	 *            a 3-values array containing [red,green,blue] values
	 */
	public void setPixel(int x, int y, int rgb[]) {
		this.setPixel(x, y, rgb[0], rgb[1], rgb[2]);
	}

	/**
	 * set target pixel color (RGB) -- color values btw 0 and 255
	 * 
	 * @param x
	 * @param y
	 * @param red
	 * @param green
	 * @param blue
	 */
	public void setPixel(int x, int y, int red, int green, int blue) {
		int colorValues;
		colorValues = 0xFF000000; // alpha set non transparent
		colorValues += red * 256 * 256; // red
		colorValues += green * 256; // green
		colorValues += blue; // blue
		this.setRGB(x, y, colorValues);
	}

	/**
	 * return target pixel color
	 * 
	 * @param x
	 * @param y
	 * @return a 3-values array containing [red,green,blue] values -- color
	 *         values btw 0 and 255
	 */
	public int[] getPixel(int x, int y) {
		int[] rgb = new int[3];
		int rawvalue = this.getRGB(x, y);
		rgb[0] = (rawvalue & 0x00FF0000) / (int) Math.pow(256, 2); // red
		rgb[1] = (rawvalue & 0x0000FF00) / 256; // green
		rgb[2] = (rawvalue & 0x000000FF); // blue
		return rgb;
	}

	// HSV methods (same as RGB but handles HSV values in and out) -- all values
	// btw [0..1]
	public double[] getPixelHSB(int x, int y) {
		int[] rgb = this.getPixel(x, y);
		float[] hsvFloat = java.awt.Color
				.RGBtoHSB(rgb[0], rgb[1], rgb[2], null);
		double[] hsv = new double[3];
		for (int i = 0; i < hsv.length; i++)
			hsv[i] = hsvFloat[i];
		return hsv;
	}

	public void setPixelHSB(int x, int y, double[] hsb) {
		this.setPixelHSB(x, y, hsb[0], hsb[1], hsb[2]);
	}

	public void setPixelHSB(int x, int y, double h, double s, double b) {
		int rgb = java.awt.Color.HSBtoRGB((float) h, (float) s, (float) b);
		this.setRGB(x, y, rgb);
	}

	/**
	 * fill screen with given color values (cls means "clear screen")
	 * 
	 * @param r
	 * @param g
	 * @param b
	 */
	public void cls(int r, int g, int b) {
		for (int x = 0; x != this.getWidth(); x++)
			for (int y = 0; y != this.getHeight(); y++)
				this.setPixel(x, y, r, g, b);
	}

	public void writeText(String __text) {
		Graphics2D g = this.createGraphics();
		g.setColor(Color.GREEN);
		g.setFont(new Font("Lucida Sans Typewriter", Font.PLAIN, 36));
		g.drawString("Hello, World!", 10, 50);
		g.dispose();
	}

	public static void main(String[] args) throws IOException {

		// build an ImageBuffer
		ImageBuffer image = new ImageBuffer(16, 16); // method 1 : call
														// constructor
		// ImageBuffer image = loadFromDisk("test"); // method 2 : image loading
		// factory

		// Set a pixel
		int[] rgb = { 255, 0, 0 };
		image.setPixel(0, 0, rgb); // method 1a : wrap-up method from
									// ImageBuffer
		// image.setPixel(0,0,255,255,255,255); // method 1b : wrap-up method
		// from ImageBuffer
		// image.setRGB(0, 0, 0xFF00FF00); // method 2 : standard method from
		// BufferedImage using only one integer value

		// various specific wrap-up methods from ImageBuffer or general
		// accessing method inherited from the BufferedImage object ...
		int w = image.getWidth();
		int h = image.getHeight();

		for (int j = 0; j != h; j++)
			for (int i = 0; i != w; i++)
				image.setPixel(i, j, (int) ((double) (i) / (double) w * 255.),
						(int) ((double) (j) / (double) h * 255.),
						(int) ((double) (j) / (double) h * 255.));

		System.out.println("number of bands : "
				+ image.getRaster().getNumBands());
		System.out.println("colors of origin pixel: " + image.getRGB(0, 0));
		rgb = image.getPixel(0, 0);
		System.out.println("colors of origin pixel (detailed) : (" + rgb[0]
				+ "," + rgb[1] + "," + rgb[2] + ")");
		System.out.println("image size is (" + w + "," + h + ")");

		// save to disk
		image.saveToDisk("testdev");
		System.out.println("file \"testdev.png\" created.");

		// display image -- you may prefer using ImageFrame if you want to
		// display an image.

		Icon icon = new ImageIcon(image);
		JLabel label = new JLabel(icon);

		final JFrame f = new JFrame("Demo");
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.getContentPane().add(label);
		f.pack();
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				f.setLocationRelativeTo(null);
				f.setVisible(true);
			}
		});

	}
}
